package com.kuson.springcloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * 使用这个模块来练习nacos的sentinel的配置模块
 *
 * 1.testA的流量控制  (/testA、/testB)
 *      1.1直接 qps每秒钟超过了1个线程访问就进行服务降级。最终结果：直接失败
 *      1.2关联 QPS每秒钟超过了1个线程访问就进行服务降级。最终结果：直接失败  B惹事==》 A兜着
 *      1.3预热 默认的的是将设置的阈值/3 （10/3）这个值是平常默认的访问流量。如果突然又大并发量的数据来时，再这的时间范围内会有一个保护的机制
 *         过了这个时间的保护的时候，就会变成设置的这个阈值。使用场景，用于秒杀系统大并发量的功能
 *      1.4 排队：当大并发量的访问的时候。一秒的时间只能。
 * 2.服务降级(/testD,/testE,/testF)
 *     2.1 服务降级-rt：配置解释：使用jmeter测试，10个线程肯定是大于5个线程并且配置了在200毫秒以内处理完成那么服务正常提供，如果超过了200毫秒在未来的1秒的时间窗口内
 *            服务跳匝，服务不可用
 *     2.2服务降级-异常比例
 *          原理：没秒的服务请求数》=5时，如果此时出现的异常数超过了设置的阈值那么服务就会降级处理。
 *          配置：在20个请求当中，如果每秒的异常比例超过了20%(0.2)那么这个服务就会进行熔断处理。此时在访问页面的时候，就不会出现错误页面，而提示服务不可用的页面。提示：(Blocked by Sentinel (flow limiting))
 *
 *     2.3服务降级-异常数
 *        原理：当请求超过了阈值的时候。在时间窗口内会进行服务降级。如果时间设置在了60秒以内，本次窗口时间内结束之后可能还会进入服务熔断
 *        配置  请求的错误数为5个，时间窗口为70秒
 *  3.热点key限流
 *    3.1热点key是监控某一个请求路劲下的某一个参数值，是使用下标来确定参数。设置了阈值之后如果超过这个阈值就会有一个兜底的方法。
 *      注解配置 ： @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
 *                  兜底的方法：public String deal_testHotKey(){}
 *      3.1.1热点key的高级配置：
 *            在热点key的某一个特殊的值请求数可以配置高于平常的请求数。这个配置的值是要在8大基本数据类型和String的类型
 *
 *
 */
@RestController
@Slf4j
public class FlowLimitController {
    /**
     * 服务限流
     * @return
     */
    @GetMapping("/testA")
    public String testA() {
        return "------testA";
    }

    /**
     * 服务限流
     * @return
     */
    @GetMapping("/testB")
    public String testB() {

        return "------testB";
    }

    /**
     * 服务熔断练习
     * @return
     */
    @GetMapping("/testD")
    public String testD()
    {
        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
        log.info("testD 测试RT");
        return "------testD";
    }

    /**
     * 异常比例
     * @return
     */
    @GetMapping("/testE")
    public String testE()
    {

        log.info("testE 测试服务降级-异常比例");
        int age = 10/0;
        return "------testE";
    }

    /**
     * 异常数
     * @return
     */
    @GetMapping("/testF")
    public String testF()
    {
        log.info("testF测试异常数");
        int age = 10/0;
        return "------testF 测试异常数";
    }

    /**
     * 热点key的监控配置
     * @param p1
     * @param p2
     * @return
     */
    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                             @RequestParam(value = "p2",required = false) String p2) {
        //int age = 10/0;
        return "------testHotKey";
    }

    //兜底方法
    public String deal_testHotKey (String p1, String p2, BlockException exception){
        return "------deal_testHotKey,o(╥﹏╥)o";
    }




}
